﻿
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// Pour en savoir plus sur le modèle d'élément Contrôle utilisateur, consultez la page http://go.microsoft.com/fwlink/?LinkId=234236

namespace SoundSynthLab.Controls
{
    public sealed partial class AnimatedKeyboard : UserControl
    {

        static List<AnimatedKeyboard> Instances = new List<AnimatedKeyboard>();
        Dictionary<int, Dictionary<int, int>> PressedNotes;
        public AnimatedKeyboard()
        {
            this.InitializeComponent();
            PressedNotes = new Dictionary<int, Dictionary<int, int>>();
            Instances.Add(this);
        }
        #region press/release note
        public static void PressNoteStatic(int octave, int note)
        {
            foreach (var instance in Instances)
            {
                instance.PressNote(octave, note);
            }
        }

        public static void ReleaseNoteStatic(int octave, int note)
        {
            foreach (var instance in Instances)
            {
                instance.ReleaseNote(octave, note);
            }
        }

        private int PrevNote = -1, PrevOctave = -1;

        public void PressNote(int octave, int note)
        {
            lock (this)
            {
                if (!PressedNotes.ContainsKey(octave))
                    PressedNotes[octave] = new Dictionary<int, int>();
                if (!PressedNotes[octave].ContainsKey(note))
                    PressedNotes[octave][note] = 0;
                PressedNotes[octave][note]++;
                UpdateGraphic();
            }
        }

        public void ReleaseNote(int octave, int note)
        {
            lock (this)
            {
                if (PressedNotes.ContainsKey(octave))
                {
                    if (PressedNotes[octave].ContainsKey(note))
                    {
                        PressedNotes[octave][note]--;
                        if (PressedNotes[octave][note] < 1) PressedNotes[octave].Remove(note);
                        UpdateGraphic();
                    }
                    if (PressedNotes[octave].Count == 0) PressedNotes.Remove(octave);
                }
            }
        }
        #endregion

        public bool IsNotePressed(int octave, int note)
        { 
            return PressedNotes.ContainsKey(octave) && PressedNotes[octave].ContainsKey(note) && (PressedNotes[octave][note]>0);
        }
        public event Action<int, int> NotePressed;
        public event Action NoteReleased;
        public async void UpdateGraphic()
        {
                await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    canvaKeyBoard.Children.Clear();
                    int OctaveCount = 3;
                    var WidthPerOctave = this.ActualWidth / OctaveCount;
                    var WidthPerNote = WidthPerOctave / 7;
                    List<int> BlackKeys = new List<int>() { 1, 3, 6, 8, 10 };
                    List<int> WhiteKeys = new List<int>() { 0, 2, 4, 5, 7, 9, 11 };
                    for (int octave = 0; octave < OctaveCount; octave++)
                    {
                        foreach (var note in WhiteKeys.Concat(BlackKeys))
                        {
                            double xPos = 0;
                            double yPos = 0;
                            double xWidth = WidthPerNote;
                            double yHeight = this.ActualHeight;
                            Windows.UI.Color color = Windows.UI.Color.FromArgb(255, 240, 240, 240);
                            if (note < 5)
                            {
                                xPos = WidthPerNote * (note / 2);
                            }
                            else
                            {
                                xPos = (WidthPerNote * 3) + WidthPerNote * ((note - 5) / 2);
                            }
                            if (BlackKeys.Any(n => n == note))
                            {
                                xPos += (WidthPerNote- (WidthPerNote / 5d));
                                xWidth = WidthPerNote / 2.5;
                                yHeight = this.ActualHeight * 0.6;
                                color = Windows.UI.Color.FromArgb(255, 60, 60, 60);
                            }
                            if (IsNotePressed(octave, note))
                            {
                                color = Windows.UI.Color.FromArgb(255, 250, 128, 20);
                            }
                            xPos += octave * WidthPerOctave;
                            DrawRectangle(xPos, yPos, xWidth, yHeight, color);
                        }
                    }
                });
        }

        private void DrawRectangle(double x1, double y1, double w, double h, Windows.UI.Color c)
        {
            Windows.UI.Xaml.Shapes.Path path = new Windows.UI.Xaml.Shapes.Path()
            {
                StrokeThickness = 4,
                Stroke = 
                    (c.R<100)?new SolidColorBrush(Windows.UI.Colors.Black):
                    new SolidColorBrush(Windows.UI.Color.FromArgb(255,128,128,128)),
                Fill=new SolidColorBrush(c)
            };
            path.Data = new RectangleGeometry {Rect = new Rect(x1, y1, w, h)};
            canvaKeyBoard.Children.Add(path);
        }

        bool isPressing;
        private void canvaKeyBoard_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            var position = e.GetCurrentPoint(canvaKeyBoard).Position;
            int OctaveCount = 3;
            var WidthPerOctave = this.ActualWidth / OctaveCount;
            var WidthPerNote = WidthPerOctave / 7;
            var octave =(int)(position.X / WidthPerOctave);
            List<int> BlackKeys = new List<int>() { 1, 3, 6, 8, 10 };
            List<int> WhiteKeys = new List<int>() { 0, 2, 4, 5, 7, 9, 11 };
            foreach (var note in BlackKeys.Concat( WhiteKeys))
            {
                double xPos = 0;
                double yPos = 0;
                double xWidth = WidthPerNote;
                double yHeight = this.ActualHeight;
                if (note < 5)
                    xPos = WidthPerNote * (note / 2);
                else
                    xPos = (WidthPerNote * 3) + WidthPerNote * ((note - 5) / 2);
                if (BlackKeys.Any(n => n == note))
                {
                    xPos += (WidthPerNote - (WidthPerNote / 5d));
                    xWidth = WidthPerNote / 2.5;
                    yHeight = this.ActualHeight * 0.6;
                }
                xPos += octave * WidthPerOctave;
                if ((position.X >= xPos) && (position.X <= xPos + xWidth) &&
                      (position.Y >= yPos) && (position.Y <= yPos + yHeight))
                {
                    if ((note != PrevNote) || (octave != PrevOctave))
                    {
                        if (isPressing)
                        {
                            canvaKeyBoard_PointerReleased(null, null);
                        }
                        isPressing = e.GetCurrentPoint(canvaKeyBoard).Properties.IsLeftButtonPressed||isPressing;
                        if (isPressing)
                        {
                            PrevNote = note;
                            PrevOctave = octave;
                            PressNote(octave, note);
                            if (NotePressed != null)
                            {

                                NotePressed(note, octave);
                            }
                        }
                    }
                    return;
                }
            }
        }

        

        private void canvaKeyBoard_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            if (isPressing)
            {
                if (PrevOctave > -1 && PrevNote > -1)
                {
                    ReleaseNote(PrevOctave, PrevNote);
                    if (NoteReleased != null) NoteReleased();
                    PrevOctave = -1;
                    PrevNote = -1;
                    isPressing = false;
                }
            }
             //if ((PlayedNote != null) && (PlayedNote.IsPlaying)) PlayedNote.Stop();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            UpdateGraphic();
        }

        
    }
}
